﻿Option Explicit On
Option Strict On

Imports System.ServiceModel


Namespace ACOM2000

    ''' <summary>
    ''' ACOM2000A Controller
    ''' </summary>
    ''' <remarks></remarks>
    <ServiceBehavior(InstanceContextMode:=ServiceModel.InstanceContextMode.Single, ConcurrencyMode:=ConcurrencyMode.Multiple)> _
    Public Class Controller
        Implements IController

#Region " Private Members "

        Private m_EventSubscribers As New Generic.List(Of IControllerCallbacks) 'List to track subscribers to callback events

        Private m_AmplifierState As New AmplifierState 'Stores the State information for the ACOM2000A
        Private m_FeatureAvailabilityState As New FeatureAvailabilityState 'Stores the state information for any UI Elements that may be used

        Private WithEvents m_Connection As Connection

        'Auto Determine Operate Mode
        Private WithEvents m_DetermineOperateModeTimer As New Timers.Timer(1000)
        Private m_DeterminingOperateMode As Boolean
        Private m_DOM_StandbyMessageReceived As Boolean
        Private m_DOM_StandbyLEDOn As Boolean

        Private m_CurrentCOMPort As String = ""
        Private m_DoNotRefresh As Boolean = False
        Private m_SupportsRemotePowerOn As Boolean = False
        Private m_RemotePowerOnMechanism As RemotePowerOnMechanism
        Private m_Connecting As Boolean = False

#End Region

#Region " Events "

        Public Event StateChanged As EventHandler
        Public Event ForwardPowerLedChanged As EventHandler(Of PowerLedChangedEventArgs)
        Public Event ReflectedPowerLedChanged As EventHandler(Of PowerLedChangedEventArgs)

#End Region

#Region " Constructor "

        ''' <summary>
        ''' Constructor
        ''' </summary>
        ''' <param name="SupportsPowerOn"></param>
        ''' <param name="DeterminingOperateMode"></param>
        ''' <param name="RemotePowerOnMechanism"></param>
        ''' <remarks></remarks>
        Public Sub New(ByVal ComPort As String, ByVal SupportsPowerOn As Boolean, ByVal DeterminingOperateMode As Boolean, ByVal RemotePowerOnMechanism As RemotePowerOnMechanism)

            'Validate ComPort isn't nothing 
            If ComPort Is Nothing Then
                Throw New ArgumentNullException("ComPort")
            End If

            m_SupportsRemotePowerOn = SupportsPowerOn
            m_DeterminingOperateMode = DeterminingOperateMode
            m_RemotePowerOnMechanism = RemotePowerOnMechanism
            m_CurrentCOMPort = ComPort.ToUpper

            If m_CurrentCOMPort.Trim = "" Then
                m_AmplifierState.CanConnect = False
            Else
                m_AmplifierState.CanConnect = True
            End If

            m_Connection = New ACOMDirector.Hardware.ACOM2000.Connection
            m_Connection.DisconnectOnTimeout = False

            RefreshStatus()

        End Sub

#End Region

#Region " Public Properties "

        ''' <summary>
        ''' The Current State of the ACOM2000A
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property State As AmplifierState
            Get
                Return m_AmplifierState
            End Get
        End Property

        ''' <summary>
        ''' The Current COM port being used to connect to the ACOM2000A
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property COMPort As String
            Get
                Return m_CurrentCOMPort
            End Get
            Set(ByVal value As String)
                If value Is Nothing Then
                    Throw New ArgumentNullException("value")
                End If

                'If the connection is open then close it and reset any state
                If Not value.ToUpper = m_CurrentCOMPort Then
                    Dim WasConnected As Boolean = False
                    If m_Connection.IsConnected Then
                        m_Connection.Disconnect()
                        m_AmplifierState = New AmplifierState
                        m_FeatureAvailabilityState = New FeatureAvailabilityState
                        WasConnected = True
                        RaiseEvent StateChanged(Me, New EventArgs)
                    End If

                    m_CurrentCOMPort = value

                    If m_CurrentCOMPort.Trim = "" Then
                        m_AmplifierState.CanConnect = False
                    Else
                        m_AmplifierState.CanConnect = True
                    End If
                    RefreshStatus()

                    If WasConnected AndAlso Not m_CurrentCOMPort = "" Then
                        Connect()
                    End If
                End If
            End Set
        End Property

        ''' <summary>
        ''' True if Remote Power on is supported
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property SupportsRemotePowerOn As Boolean
            Get
                Return m_SupportsRemotePowerOn
            End Get
            Set(ByVal value As Boolean)
                m_SupportsRemotePowerOn = value
            End Set
        End Property

        ''' <summary>
        ''' The Mechanism used for turning on the Amplifier
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property RemotePowerOnMechanism As RemotePowerOnMechanism
            Get
                Return m_RemotePowerOnMechanism
            End Get
            Set(ByVal value As RemotePowerOnMechanism)
                m_RemotePowerOnMechanism = value
            End Set
        End Property

        ''' <summary>
        ''' The Current Feature Availability State
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property FeatureAvailabilityState As FeatureAvailabilityState
            Get
                Return m_FeatureAvailabilityState
            End Get
        End Property

#End Region

#Region " ACOM Events "

        Private Sub m_Connection_ACOM2000ADetected(ByVal sender As Object, ByVal e As DeviceDetectedEventArgs) Handles m_Connection.ACOM2000ADetected
            'We have a connection so power must be on
            m_AmplifierState.PowerLED = LedStatus.On
            m_AmplifierState.PowerState = PowerState.Connected

            'Get some initial info from the ACOM2000A
            m_Connection.GetCurrentFrequencySegmentInfo()

            If m_DeterminingOperateMode Then
                DetermineOperateMode()
            End If
        End Sub

        Private Sub m_Connection_ConnectionClosed(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_Connection.ConnectionClosed
            m_AmplifierState.PowerState = PowerState.Disconnected
            RefreshStatus()
        End Sub

        Private Sub m_Connection_AirTemperatureChanged(ByVal sender As Object, ByVal e As AirTemperatureChangedEventArgs) Handles m_Connection.AirTemperatureChanged
            m_AmplifierState.CurrentAirTemp = e.Bars
            RefreshStatus()
        End Sub

        Private Sub m_Connection_RCUIsMeasuring(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_Connection.RCUIsMeasuring
            If m_AmplifierState.IsMeasuring = True Then
                m_AmplifierState.IsMeasuring = False
            End If
        End Sub

        Private Sub m_Connection_MeasurementMetricUpdated(ByVal sender As Object, ByVal e As MeasurementMetricUpdatedEventArgs) Handles m_Connection.MeasurementMetricUpdated
            If m_AmplifierState.MetricA = e.Metric Then
                m_AmplifierState.MetricAValue = e.Value
            End If
            If m_AmplifierState.MetricB = e.Metric Then
                m_AmplifierState.MetricBValue = e.Value
            End If
        End Sub

        Private Sub m_Connection_LEDStatusUpdate(ByVal sender As Object, ByVal e As LEDStatusEventArgs) Handles m_Connection.LEDStatusUpdate
            m_DoNotRefresh = True

            m_AmplifierState.OperateLED = e.OperateLED
            m_AmplifierState.StandbyLED = e.StandbyLED
            m_AmplifierState.PlateLED = e.PlateLED
            m_AmplifierState.DriveLED = e.DriveLED
            m_AmplifierState.HeaterLED = e.HeaterLED
            m_AmplifierState.ProtectionLED = e.ProtectionLED

            If m_DeterminingOperateMode Then
                If e.StandbyLED = LedStatus.On Then
                    m_DOM_StandbyLEDOn = True
                End If
            End If

            m_DoNotRefresh = False
            RefreshStatus()
        End Sub

        Private Sub m_Connection_PowerOffComplete(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_Connection.PowerOffComplete
            If SupportsRemotePowerOn Then
                'If remote power on is supported then set state as powered off
                m_AmplifierState.PowerState = PowerState.PoweredOff
            Else
                'If Remote power on is not supported then disconnect the COM port and set the state accordingly 
                m_Connection.Disconnect()
                m_AmplifierState.PowerState = PowerState.Disconnected
            End If
            RefreshStatus()
        End Sub

        Private Sub m_Connection_PowerOffCoolingTubes(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_Connection.PowerOffCoolingTubes
            m_AmplifierState.PowerState = PowerState.PoweringOffCoolingTubes
            RefreshStatus()
        End Sub

        Private Sub m_Connection_PowerOffExecuted(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_Connection.PowerOffExecuted
            m_AmplifierState.PowerState = PowerState.PoweringOff
            RefreshStatus()
        End Sub

        Private Sub m_Connection_PowerOnExecuted(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_Connection.PowerOnExecuted
            m_AmplifierState.PowerState = PowerState.PoweringOn
            RefreshStatus()
        End Sub

        Private Sub m_Connection_HVOnExecuted(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_Connection.HVOnExecuted
            'HV is now ready, so treat the ACOM as on and connected
            m_AmplifierState.PowerState = PowerState.Connected
            RefreshStatus()
        End Sub

        Private Sub m_Connection_ConnectionTimeout(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_Connection.ConnectionTimeout
            'We have timed out trying to detect an ACOM2000
            If SupportsRemotePowerOn Then
                'If we support remote power on then assume it's turned off
                m_AmplifierState.PowerState = PowerState.PoweredOff
            Else
                'If remote power on is not supported then assume we are disconnected
                m_AmplifierState.PowerState = PowerState.Disconnected
                m_Connection.Disconnect()
            End If
            RefreshStatus()
        End Sub

        Private Sub m_Connection_OperateModeOn(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_Connection.OperateModeOn
            m_AmplifierState.OperateMode = OperateModes.Operate
            RefreshStatus()
        End Sub

        Private Sub m_Connection_StandByModeOn(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_Connection.StandbyModeOn
            If m_DeterminingOperateMode Then
                m_DOM_StandbyMessageReceived = True
            End If

            m_AmplifierState.OperateMode = OperateModes.Standby
            RefreshStatus()
        End Sub

        Private Sub m_Connection_BandFrequencyChanged(ByVal sender As Object, ByVal e As BandFrequencyEventArgs) Handles m_Connection.BandFrequencyChanged
            m_AmplifierState.Band = e.Band
            m_AmplifierState.Segment = e.Segment
            m_AmplifierState.USRMode = e.USRMode
            m_AmplifierState.AntennaNumber = e.AntennaNumber
            RefreshStatus()
        End Sub

        Private Sub m_Connection_ReflectedPowerLedUpdated(ByVal sender As Object, ByVal e As PowerLedChangedEventArgs) Handles m_Connection.ReflectedPowerLedUpdated
            If m_EventSubscribers.Count = 0 Then Return

            'Track Dead Callback handlers
            Dim DeadCallbackHandlers As New Generic.List(Of IControllerCallbacks)

            'Dispatch the event
            For Each CallbackHandler As IControllerCallbacks In m_EventSubscribers
                Try
                    'CallbackHandler.ReflectedPowerLedChangedCallback(e)
                    Dim LambdaCallbackHandler As IControllerCallbacks = CallbackHandler
                    CallbackHandler.BeginOnReflectedPowerLedChanged(e, (Sub(ar As IAsyncResult) LambdaCallbackHandler.EndOnReflectedPowerLedChanged(ar)), Nothing)
                Catch ex As System.ServiceModel.CommunicationException
                    DeadCallbackHandlers.Add(CallbackHandler)
                End Try
            Next

            'Remove any dead callback handlers
            If DeadCallbackHandlers.Count > 0 Then
                For Each item As IControllerCallbacks In DeadCallbackHandlers
                    m_EventSubscribers.Remove(item)
                Next
            End If
        End Sub

        Private Sub m_Connection_ForwardPowerLedUpdated(ByVal sender As Object, ByVal e As PowerLedChangedEventArgs) Handles m_Connection.ForwardPowerLedUpdated
            If m_EventSubscribers.Count = 0 Then Return

            'Track Dead Callback handlers
            Dim DeadCallbackHandlers As New Generic.List(Of IControllerCallbacks)

            'Dispatch the event
            For Each CallbackHandler As IControllerCallbacks In m_EventSubscribers
                Try
                    'CallbackHandler.ForwardPowerLedChangedCallback(e)
                    Dim LambdaCallbackHandler As IControllerCallbacks = CallbackHandler
                    CallbackHandler.BeginOnForwardPowerLedChanged(e, (Sub(ar As IAsyncResult) LambdaCallbackHandler.EndOnForwardPowerLedChanged(ar)), Nothing)
                Catch ex As System.ServiceModel.CommunicationException
                    DeadCallbackHandlers.Add(CallbackHandler)
                End Try
            Next

            'Remove any dead callback handlers
            If DeadCallbackHandlers.Count > 0 Then
                For Each item As IControllerCallbacks In DeadCallbackHandlers
                    m_EventSubscribers.Remove(item)
                Next
            End If
        End Sub

        Private Sub m_Connection_AmplifierError(ByVal sender As Object, ByVal e As AmplifierErrorEventArgs) Handles m_Connection.AmplifierError
            m_AmplifierState.PowerStatePriorToError = m_AmplifierState.PowerState

            Dim ErrorText() As String = e.Message.Split("|"c)
            m_AmplifierState.CurrentErrorMessageLine1 = ErrorText(0).Replace("$var$", e.ParameterValue)
            If ErrorText.Length = 2 Then
                m_AmplifierState.CurrentErrorMessageLine2 = ErrorText(1).Replace("$var$", e.ParameterValue)
            Else
                m_AmplifierState.CurrentErrorMessageLine2 = ""
            End If

            If m_AmplifierState.CurrentErrorMessageLine1.Length < 20 Then
                Dim Spaces As Integer = 20 - m_AmplifierState.CurrentErrorMessageLine1.Length
                If Spaces Mod 2 = 0 Then
                    m_AmplifierState.CurrentErrorMessageLine1 = StrDup(Spaces \ 2, " ") & m_AmplifierState.CurrentErrorMessageLine1 & StrDup(Spaces \ 2, " ")
                Else
                    Spaces = Spaces - 1
                    m_AmplifierState.CurrentErrorMessageLine1 = StrDup(Spaces \ 2, " ") & m_AmplifierState.CurrentErrorMessageLine1 & StrDup(Spaces \ 2, " ") & " "
                End If
            End If
            If m_AmplifierState.CurrentErrorMessageLine2.Length < 20 Then
                Dim Spaces As Integer = 20 - m_AmplifierState.CurrentErrorMessageLine2.Length
                If Spaces Mod 2 = 0 Then
                    m_AmplifierState.CurrentErrorMessageLine2 = StrDup(Spaces \ 2, " ") & m_AmplifierState.CurrentErrorMessageLine2 & StrDup(Spaces \ 2, " ")
                Else
                    Spaces = Spaces - 1
                    m_AmplifierState.CurrentErrorMessageLine2 = StrDup(Spaces \ 2, " ") & m_AmplifierState.CurrentErrorMessageLine2 & StrDup(Spaces \ 2, " ") & " "
                End If
            End If

            m_AmplifierState.PowerState = PowerState.ErrorState
        End Sub

#End Region

#Region " Private Methods "

        ''' <summary>
        ''' Refreshes the amplifier state object
        ''' </summary>
        ''' <remarks></remarks>
        Private Sub RefreshStatus()
            If m_DoNotRefresh Then Exit Sub

            If m_Connecting Then
                m_AmplifierState.DisplayLine1 = "     CONNECTING     "
                m_AmplifierState.DisplayLine2 = "    PLEASE WAIT...  "
                m_AmplifierState.DisplayLine3 = "                    "
                m_AmplifierState.DisplayLine4 = "                    "

                'Turn off all LED's
                m_AmplifierState.PowerLED = LedStatus.Off
                m_AmplifierState.OperateLED = LedStatus.Off
                m_AmplifierState.StandbyLED = LedStatus.Off
                m_AmplifierState.PlateLED = LedStatus.Off
                m_AmplifierState.DriveLED = LedStatus.Off
                m_AmplifierState.HeaterLED = LedStatus.Off
                m_AmplifierState.ProtectionLED = LedStatus.Off

                m_FeatureAvailabilityState.OperateStandbyEnabled = False
                m_FeatureAvailabilityState.OnOffEnabled = False
                m_FeatureAvailabilityState.SelectAntenna0Enabled = False
                m_FeatureAvailabilityState.SelectAntenna1Enabled = False
                m_FeatureAvailabilityState.SelectAntenna2Enabled = False
                m_FeatureAvailabilityState.SelectAntenna3Enabled = False
                m_FeatureAvailabilityState.SelectAntenna4Enabled = False
                m_FeatureAvailabilityState.SelectAntenna5Enabled = False
                m_FeatureAvailabilityState.SelectAntenna6Enabled = False
                m_FeatureAvailabilityState.SelectAntenna7Enabled = False
                m_FeatureAvailabilityState.SelectAntenna8Enabled = False
                m_FeatureAvailabilityState.SelectAntenna9Enabled = False
                m_FeatureAvailabilityState.StartMeasuringEnabled = False
                m_FeatureAvailabilityState.StopMeasuringEnabled = False
                m_FeatureAvailabilityState.MetricASelectionEnabled = False
                m_FeatureAvailabilityState.MetricBSelectionEnabled = False
                m_FeatureAvailabilityState.DisconnectEnabled = True
                m_FeatureAvailabilityState.ConnectEnabled = False

            Else

                Select Case m_AmplifierState.PowerState
                    Case PowerState.Disconnected
                        m_AmplifierState.DisplayLine1 = "    DISCONNECTED    "
                        m_AmplifierState.DisplayLine2 = "                    "
                        m_AmplifierState.DisplayLine3 = "                    "
                        m_AmplifierState.DisplayLine4 = "                    "

                        'Turn off all LED's
                        m_AmplifierState.PowerLED = LedStatus.Off
                        m_AmplifierState.OperateLED = LedStatus.Off
                        m_AmplifierState.StandbyLED = LedStatus.Off
                        m_AmplifierState.PlateLED = LedStatus.Off
                        m_AmplifierState.DriveLED = LedStatus.Off
                        m_AmplifierState.HeaterLED = LedStatus.Off
                        m_AmplifierState.ProtectionLED = LedStatus.Off

                        m_FeatureAvailabilityState.OperateStandbyEnabled = False
                        m_FeatureAvailabilityState.OnOffEnabled = False
                        m_FeatureAvailabilityState.SelectAntenna0Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna1Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna2Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna3Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna4Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna5Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna6Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna7Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna8Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna9Enabled = False
                        m_FeatureAvailabilityState.StartMeasuringEnabled = False
                        m_FeatureAvailabilityState.StopMeasuringEnabled = False
                        m_FeatureAvailabilityState.MetricASelectionEnabled = False
                        m_FeatureAvailabilityState.MetricBSelectionEnabled = False
                        m_FeatureAvailabilityState.DisconnectEnabled = False

                        If m_Connecting Or Not m_AmplifierState.CanConnect Then
                            m_FeatureAvailabilityState.ConnectEnabled = False
                        Else
                            m_FeatureAvailabilityState.ConnectEnabled = True
                        End If


                    Case PowerState.Connecting
                        m_AmplifierState.DisplayLine1 = "     CONNECTING     "
                        m_AmplifierState.DisplayLine2 = "    PLEASE WAIT...  "
                        m_AmplifierState.DisplayLine3 = "                    "
                        m_AmplifierState.DisplayLine4 = "                    "

                        'Turn off all LED's
                        m_AmplifierState.PowerLED = LedStatus.Off
                        m_AmplifierState.OperateLED = LedStatus.Off
                        m_AmplifierState.StandbyLED = LedStatus.Off
                        m_AmplifierState.PlateLED = LedStatus.Off
                        m_AmplifierState.DriveLED = LedStatus.Off
                        m_AmplifierState.HeaterLED = LedStatus.Off
                        m_AmplifierState.ProtectionLED = LedStatus.Off

                        m_FeatureAvailabilityState.OperateStandbyEnabled = False
                        m_FeatureAvailabilityState.OnOffEnabled = False
                        m_FeatureAvailabilityState.SelectAntenna0Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna1Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna2Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna3Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna4Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna5Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna6Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna7Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna8Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna9Enabled = False
                        m_FeatureAvailabilityState.StartMeasuringEnabled = False
                        m_FeatureAvailabilityState.StopMeasuringEnabled = False
                        m_FeatureAvailabilityState.MetricASelectionEnabled = False
                        m_FeatureAvailabilityState.MetricBSelectionEnabled = False
                        m_FeatureAvailabilityState.DisconnectEnabled = True
                        m_FeatureAvailabilityState.ConnectEnabled = False

                    Case PowerState.PoweredOff
                        m_AmplifierState.DisplayLine1 = "    POWER IS OFF    "
                        m_AmplifierState.DisplayLine2 = "                    "
                        m_AmplifierState.DisplayLine3 = "                    "
                        m_AmplifierState.DisplayLine4 = "                    "

                        'Turn off all LED's
                        m_AmplifierState.PowerLED = LedStatus.Off
                        m_AmplifierState.OperateLED = LedStatus.Off
                        m_AmplifierState.StandbyLED = LedStatus.Off
                        m_AmplifierState.PlateLED = LedStatus.Off
                        m_AmplifierState.DriveLED = LedStatus.Off
                        m_AmplifierState.HeaterLED = LedStatus.Off
                        m_AmplifierState.ProtectionLED = LedStatus.Off

                        m_FeatureAvailabilityState.OperateStandbyEnabled = False
                        If SupportsRemotePowerOn Then
                            m_FeatureAvailabilityState.OnOffEnabled = True
                        Else
                            m_FeatureAvailabilityState.OnOffEnabled = False
                        End If
                        m_FeatureAvailabilityState.SelectAntenna0Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna1Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna2Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna3Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna4Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna5Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna6Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna7Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna8Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna9Enabled = False
                        m_FeatureAvailabilityState.StartMeasuringEnabled = False
                        m_FeatureAvailabilityState.StopMeasuringEnabled = False
                        m_FeatureAvailabilityState.MetricASelectionEnabled = False
                        m_FeatureAvailabilityState.MetricBSelectionEnabled = False

                        m_FeatureAvailabilityState.DisconnectEnabled = True
                        m_FeatureAvailabilityState.ConnectEnabled = False

                    Case PowerState.PoweringOff
                        m_AmplifierState.DisplayLine1 = "    POWERING OFF    "
                        m_AmplifierState.DisplayLine2 = "    PLEASE WAIT...  "
                        m_AmplifierState.DisplayLine3 = "                    "
                        m_AmplifierState.DisplayLine4 = "                    "

                        m_AmplifierState.PowerLED = LedStatus.On
                        m_AmplifierState.OperateLED = LedStatus.Off
                        m_AmplifierState.StandbyLED = LedStatus.Off
                        m_AmplifierState.PlateLED = LedStatus.Off
                        m_AmplifierState.DriveLED = LedStatus.Off
                        m_AmplifierState.HeaterLED = LedStatus.Off
                        m_AmplifierState.ProtectionLED = LedStatus.Off

                        m_FeatureAvailabilityState.OperateStandbyEnabled = False
                        m_FeatureAvailabilityState.OnOffEnabled = False
                        m_FeatureAvailabilityState.SelectAntenna0Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna1Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna2Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna3Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna4Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna5Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna6Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna7Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna8Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna9Enabled = False
                        m_FeatureAvailabilityState.StartMeasuringEnabled = False
                        m_FeatureAvailabilityState.StopMeasuringEnabled = False
                        m_FeatureAvailabilityState.MetricASelectionEnabled = False
                        m_FeatureAvailabilityState.MetricBSelectionEnabled = False

                        m_FeatureAvailabilityState.DisconnectEnabled = True
                        m_FeatureAvailabilityState.ConnectEnabled = False

                    Case PowerState.PoweringOffCoolingTubes
                        m_AmplifierState.DisplayLine1 = "    COOLING TUBES   "
                        m_AmplifierState.DisplayLine2 = "    PLEASE WAIT...  "
                        m_AmplifierState.DisplayLine3 = "                    "
                        m_AmplifierState.DisplayLine4 = "                    "

                        m_AmplifierState.PowerLED = LedStatus.On
                        m_AmplifierState.OperateLED = LedStatus.Off
                        m_AmplifierState.StandbyLED = LedStatus.Off
                        m_AmplifierState.PlateLED = LedStatus.Off
                        m_AmplifierState.DriveLED = LedStatus.Off
                        m_AmplifierState.HeaterLED = LedStatus.Off
                        m_AmplifierState.ProtectionLED = LedStatus.Off

                        m_FeatureAvailabilityState.OperateStandbyEnabled = False
                        m_FeatureAvailabilityState.OnOffEnabled = False
                        m_FeatureAvailabilityState.SelectAntenna0Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna1Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna2Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna3Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna4Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna5Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna6Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna7Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna8Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna9Enabled = False
                        m_FeatureAvailabilityState.StartMeasuringEnabled = False
                        m_FeatureAvailabilityState.StopMeasuringEnabled = False
                        m_FeatureAvailabilityState.MetricASelectionEnabled = False
                        m_FeatureAvailabilityState.MetricBSelectionEnabled = False

                        m_FeatureAvailabilityState.DisconnectEnabled = True
                        m_FeatureAvailabilityState.ConnectEnabled = False

                    Case PowerState.PoweringOn
                        m_AmplifierState.DisplayLine1 = "POWER ON IN PROGRESS"
                        m_AmplifierState.DisplayLine2 = "    PLEASE WAIT...  "
                        m_AmplifierState.DisplayLine3 = "                    "
                        m_AmplifierState.DisplayLine4 = "                    "

                        m_AmplifierState.PowerLED = LedStatus.On
                        m_AmplifierState.OperateLED = LedStatus.Off
                        m_AmplifierState.StandbyLED = LedStatus.Off
                        m_AmplifierState.PlateLED = LedStatus.Off
                        m_AmplifierState.DriveLED = LedStatus.Off
                        m_AmplifierState.HeaterLED = LedStatus.Off
                        m_AmplifierState.ProtectionLED = LedStatus.Off

                        m_FeatureAvailabilityState.OperateStandbyEnabled = False
                        m_FeatureAvailabilityState.OnOffEnabled = False
                        m_FeatureAvailabilityState.SelectAntenna0Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna1Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna2Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna3Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna4Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna5Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna6Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna7Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna8Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna9Enabled = False
                        m_FeatureAvailabilityState.StartMeasuringEnabled = False
                        m_FeatureAvailabilityState.StopMeasuringEnabled = False
                        m_FeatureAvailabilityState.MetricASelectionEnabled = False
                        m_FeatureAvailabilityState.MetricBSelectionEnabled = False

                        m_FeatureAvailabilityState.DisconnectEnabled = True
                        m_FeatureAvailabilityState.ConnectEnabled = False

                    Case PowerState.ErrorState
                        m_AmplifierState.DisplayLine1 = m_AmplifierState.CurrentErrorMessageLine1
                        m_AmplifierState.DisplayLine2 = m_AmplifierState.CurrentErrorMessageLine2

                        m_FeatureAvailabilityState.OperateStandbyEnabled = True
                        m_FeatureAvailabilityState.OnOffEnabled = True
                        m_FeatureAvailabilityState.SelectAntenna0Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna1Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna2Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna3Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna4Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna5Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna6Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna7Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna8Enabled = False
                        m_FeatureAvailabilityState.SelectAntenna9Enabled = False
                        m_FeatureAvailabilityState.StartMeasuringEnabled = False
                        m_FeatureAvailabilityState.StopMeasuringEnabled = False
                        m_FeatureAvailabilityState.MetricASelectionEnabled = False
                        m_FeatureAvailabilityState.MetricBSelectionEnabled = False

                        m_FeatureAvailabilityState.DisconnectEnabled = True
                        m_FeatureAvailabilityState.ConnectEnabled = False

                    Case PowerState.Connected

                        m_FeatureAvailabilityState.OnOffEnabled = True
                        m_FeatureAvailabilityState.OperateStandbyEnabled = True
                        m_FeatureAvailabilityState.SelectAntenna0Enabled = True
                        m_FeatureAvailabilityState.SelectAntenna1Enabled = True
                        m_FeatureAvailabilityState.SelectAntenna2Enabled = True
                        m_FeatureAvailabilityState.SelectAntenna3Enabled = True
                        m_FeatureAvailabilityState.SelectAntenna4Enabled = True
                        m_FeatureAvailabilityState.SelectAntenna5Enabled = True
                        m_FeatureAvailabilityState.SelectAntenna6Enabled = True
                        m_FeatureAvailabilityState.SelectAntenna7Enabled = True
                        m_FeatureAvailabilityState.SelectAntenna8Enabled = True
                        m_FeatureAvailabilityState.SelectAntenna9Enabled = True

                        m_FeatureAvailabilityState.DisconnectEnabled = True
                        m_FeatureAvailabilityState.ConnectEnabled = False

                        Dim TopLine As String = "£C" & StrDup(m_AmplifierState.CurrentAirTemp, "¬"c) & StrDup(13 - m_AmplifierState.CurrentAirTemp, "_"c) & " "
                        If m_AmplifierState.OperateMode = OperateModes.Standby Then
                            TopLine &= "STBY"
                        Else
                            TopLine &= "OPER"
                        End If
                        m_AmplifierState.DisplayLine1 = TopLine

                        Dim Line2 As String
                        If m_AmplifierState.Segment IsNot Nothing Then
                            Line2 = (m_AmplifierState.Segment.LowerFrequency / 1000).ToString("00.000") & "-" & (m_AmplifierState.Segment.UpperFrequency / 1000).ToString("00.000") & " "
                        Else
                            Line2 = "UNKNOWN SEG   "
                        End If

                        If m_AmplifierState.AntennaNumber = 0 Then
                            Line2 &= "AM "
                        Else
                            Line2 &= "A" & m_AmplifierState.AntennaNumber.ToString() & " "
                        End If

                        If m_AmplifierState.USRMode Then
                            Line2 &= "USR"
                        Else
                            Line2 &= "DEF"
                        End If
                        m_AmplifierState.DisplayLine2 = Line2


                        Dim MeasurementTitleLine As String = "                    "
                        Dim MeasurementValueLine As String = "                    "
                        If m_AmplifierState.IsMeasuring Then
                            m_FeatureAvailabilityState.StartMeasuringEnabled = False
                            m_FeatureAvailabilityState.StopMeasuringEnabled = True

                            MeasurementTitleLine = " " & Connection.GetMeasurementTitle(m_AmplifierState.MetricA) & "  " & Connection.GetMeasurementTitle(m_AmplifierState.MetricB) & " "
                            MeasurementValueLine = " " & m_AmplifierState.MetricAValue & StrDup(8 - m_AmplifierState.MetricAValue.Length, " "c) & "  " & m_AmplifierState.MetricBValue & StrDup(8 - m_AmplifierState.MetricBValue.Length, " "c) & " "
                        Else
                            m_FeatureAvailabilityState.StartMeasuringEnabled = True
                            m_FeatureAvailabilityState.StopMeasuringEnabled = False
                        End If
                        m_AmplifierState.DisplayLine3 = MeasurementTitleLine
                        m_AmplifierState.DisplayLine4 = MeasurementValueLine

                        m_FeatureAvailabilityState.MetricASelectionEnabled = True
                        m_FeatureAvailabilityState.MetricBSelectionEnabled = True

                End Select

            End If


            'Dispatch State Changed Events
            If m_EventSubscribers.Count = 0 Then Return

            'Track Dead Callback handlers
            Dim DeadCallbackHandlers As New Generic.List(Of IControllerCallbacks)

            'Dispatch the event
            For Each CallbackHandler As IControllerCallbacks In m_EventSubscribers
                Try
                    'CallbackHandler.StateChangedCallback()
                    Dim LambdaCallbackHandler As IControllerCallbacks = CallbackHandler
                    CallbackHandler.BeginOnStateChanged((Sub(ar As IAsyncResult) LambdaCallbackHandler.EndOnStateChanged(ar)), Nothing)
                Catch ex As CommunicationException
                    DeadCallbackHandlers.Add(CallbackHandler)
                End Try
            Next

            'Remove any dead callback handlers
            If DeadCallbackHandlers.Count > 0 Then
                For Each item As IControllerCallbacks In DeadCallbackHandlers
                    m_EventSubscribers.Remove(item)
                Next
            End If

        End Sub

        Private Sub DetermineOperateMode()
            m_DeterminingOperateMode = True
            m_DOM_StandbyLEDOn = False
            m_DOM_StandbyMessageReceived = False

            m_Connection.EnterStandbyMode()
            m_DetermineOperateModeTimer.Start()
        End Sub

        Private Sub m_DetermineOperateModeTimer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles m_DetermineOperateModeTimer.Elapsed
            m_DetermineOperateModeTimer.Stop()
            m_DeterminingOperateMode = False

            If m_DOM_StandbyLEDOn And m_DOM_StandbyMessageReceived Then
                'Mode was operate
                m_Connection.EnterOperateMode()
            Else
                'Mode was standby
                m_AmplifierState.StandbyLED = LedStatus.On
            End If
        End Sub

#End Region

#Region " IController Implementation "

        ''' <summary>
        ''' Connects to the amplifier
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub Connect() Implements IController.Connect
            m_Connecting = True
            m_FeatureAvailabilityState.ConnectEnabled = False
            m_FeatureAvailabilityState.DisconnectEnabled = True
            RefreshStatus()
            If m_Connection.IsConnected Then
                m_Connection.Disconnect()
            End If
            m_AmplifierState.PowerState = PowerState.Connecting
            m_Connecting = False
            m_Connection.Connect(m_CurrentCOMPort)
        End Sub

        ''' <summary>
        ''' Disconnects from the amplifier
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub Disconnect() Implements IController.Disconnect
            m_Connection.Disconnect()
            m_FeatureAvailabilityState.ConnectEnabled = True
            m_FeatureAvailabilityState.DisconnectEnabled = False
            m_Connection.Disconnect()
        End Sub

        ''' <summary>
        ''' Subscribes the caller to the callback events
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub SubscribeEvents() Implements IController.SubscribeEvents
            'Get the callback object from the calling client
            Dim callback As IControllerCallbacks = OperationContext.Current.GetCallbackChannel(Of IControllerCallbacks)()

            'Subscribe the caller from the events
            If Not m_EventSubscribers.Contains(callback) Then
                m_EventSubscribers.Add(callback)
            End If
        End Sub

        ''' <summary>
        ''' Unsubscribes the caller from the callback events
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub UnsubscribeEvents() Implements IController.UnsubscribeEvents
            'Get the callback object from the calling client
            Dim callback As IControllerCallbacks = OperationContext.Current.GetCallbackChannel(Of IControllerCallbacks)()

            'Unsubscribe the caller from the events
            If m_EventSubscribers.Contains(callback) Then
                m_EventSubscribers.Remove(callback)
            End If
        End Sub

        ''' <summary>
        ''' Returns the Current COM Port being used
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function GetCOMPort() As String Implements IController.GetCOMPort
            Return COMPort
        End Function


        ''' <summary>
        ''' Returns True if the COM Port is open
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function GetCOMPortOpen() As Boolean Implements IController.GetCOMPortOpen
            If m_Connection IsNot Nothing Then
                Return m_Connection.IsConnected
            Else
                Return False
            End If
        End Function

        ''' <summary>
        ''' Returns the current state of the amplifier
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function GetState() As AmplifierState Implements IController.GetState
            Return m_AmplifierState
        End Function

        ''' <summary>
        ''' Returns true if the amplifier supports remote power on
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function GetSupportsRemotePowerOn() As Boolean Implements IController.GetSupportsRemotePowerOn
            Return SupportsRemotePowerOn
        End Function

        ''' <summary>
        ''' Returns the feature availability state
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function GetFeatureAvailabilityState() As FeatureAvailabilityState Implements IController.GetFeatureAvailabilityState
            Return m_FeatureAvailabilityState
        End Function


        ''' <summary>
        ''' Switches the amplifier between operate and standby
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub OperateStandby() Implements IController.OperateStandby
            If m_AmplifierState.PowerState = PowerState.ErrorState Then
                m_AmplifierState.PowerState = m_AmplifierState.PowerStatePriorToError
            End If

            If m_AmplifierState.OperateMode = OperateModes.Standby Then
                m_Connection.EnterOperateMode()
            Else
                m_Connection.EnterStandbyMode()
            End If
        End Sub

        ''' <summary>
        ''' Turns the amplifier on or off
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub OnOff() Implements IController.OnOff
            'If the power is already on then turn it off?
            If m_AmplifierState.PowerState = PowerState.Connected Then
                m_Connection.TurnAmplifierOff()
            ElseIf m_AmplifierState.PowerState = PowerState.PoweredOff Then
                If SupportsRemotePowerOn Then
                    m_Connection.PerformRemotePowerOn(m_RemotePowerOnMechanism)
                End If
            End If
        End Sub

        ''' <summary>
        ''' Selects a specified Antenna Number
        ''' </summary>
        ''' <param name="AntennaNumber">The antenna number to select between 0 and 9</param>
        ''' <remarks></remarks>
        Public Sub SelectAntenna(AntennaNumber As Integer) Implements IController.SelectAntenna
            If AntennaNumber < 0 Or AntennaNumber > 9 Then
                Throw New ArgumentOutOfRangeException("AntennaNumber", "Antenna Number must be between 0 and 9 but number " & AntennaNumber.ToString() & " was specified")
            End If

            m_Connection.SelectAntenna(AntennaNumber)
        End Sub



        ''' <summary>
        ''' Sets the current frequency of the Amplifier
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub SetFrequencyBand(ByVal FrequencyHertz As Integer) Implements IController.SetFrequencyBand
            If m_Connection.IsConnected Then
                m_Connection.SetFrequencyBand(FrequencyHertz)
            End If
        End Sub


        ''' <summary>
        ''' Changes the B Metric to the one specified
        ''' </summary>
        ''' <param name="Metric">The measurement metric to set</param>
        ''' <remarks></remarks>
        Public Sub SetMetricB(ByVal Metric As MeasurementMetricTypes) Implements IController.SetMetricB
            m_AmplifierState.MetricB = Metric
            If m_AmplifierState.IsMeasuring Then
                m_Connection.StartMeasurement(m_AmplifierState.MetricA, m_AmplifierState.MetricB)
            End If
        End Sub

        ''' <summary>
        ''' Changes the A Metric to the one specified
        ''' </summary>
        ''' <param name="Metric">The measurement metric to set</param>
        ''' <remarks></remarks>
        Public Sub SetMetricA(ByVal Metric As MeasurementMetricTypes) Implements IController.SetMetricA
            m_AmplifierState.MetricA = Metric
            If m_AmplifierState.IsMeasuring Then
                m_Connection.StartMeasurement(m_AmplifierState.MetricA, m_AmplifierState.MetricB)
            End If
        End Sub

        ''' <summary>
        ''' Stops the ACOM 2000 performing metric measurements
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub StopMeasuring() Implements IController.StopMeasuring
            m_Connection.StopMeasuring()
            m_FeatureAvailabilityState.StopMeasuringEnabled = False
            m_FeatureAvailabilityState.StartMeasuringEnabled = True
            m_AmplifierState.IsMeasuring = False
        End Sub

        ''' <summary>
        ''' Tells the ACOM 2000 to start measuring the specified metrics
        ''' </summary>
        ''' <param name="MetricA"></param>
        ''' <param name="MetricB"></param>
        ''' <remarks></remarks>
        Public Sub StartMeasuring(ByVal MetricA As MeasurementMetricTypes, ByVal MetricB As MeasurementMetricTypes) Implements IController.StartMeasuring

            m_AmplifierState.MetricA = MetricA
            m_AmplifierState.MetricB = MetricB
            m_Connection.StartMeasurement(m_AmplifierState.MetricA, m_AmplifierState.MetricB)

            m_FeatureAvailabilityState.StopMeasuringEnabled = True
            m_FeatureAvailabilityState.StartMeasuringEnabled = False
            m_AmplifierState.IsMeasuring = True

        End Sub

#End Region

    End Class

End Namespace